/***************************************************************************************************
 *Copyright(C),2010-2017,Sumscope
 *FileName	:  TinyString.h
 *Author	:  scofined.qi
 *Version	:  1.0
 *Date		:  2020/06/12
 *Desc		:  //用于主要说明此程序文件完成的主要功能
 *Relation :
 *Others	:  //其他内容说明
 *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
 *History	:
 * //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
 ***************************************************************************************************/
#pragma once

#include <string.h>

#include <string>

#include "../core.h"
namespace qb {
namespace base {
/*
        与KeyString的异同:
        KeyString在指针指向一块字符串的时候,额外分配了1到2个字节,用于
        在字符串前面存储字符串的长度
        TinyString则没有,直接指针指向字符串,如果需要长度,则需要strlen来计算

        为什么要这么做?
        部分场景下,原先键为std::string,那么通常有std::string作为参数的
        获取接口,如果以KeyString为键,那么每次查找都必须多一次
        从std::string到KeyString的转化,导致多一次内存分配
        为了避免这个多余的内存分配,必须移除长度编码
        然后配合TempTinyString来搭配使用
*/
class S_CORE_EXPORT TinyString {
  typedef TinyString ThisType;

 public:
  enum : uint64_t {
    MostBitFlag = (sizeof(uintptr_t) == 4 ? 0x80000000 : 0x8000000000000000LL),
    LowBitMask = 0x7F,  // 首个字符的第七位掩码
    TinyLength = 1 << 7,  // 短字符串长度,超过此值需要用2个字符存储长度
    MaxLength = (1 << 15) - 1  // 最大字符串长度,长于此值截断
  };

 protected:
  union {
    const char* m_data;  // 0结尾的指针,最高位为1,获取真实指针需要移除
    char m_raw[4];  // 存储不超过3个字符的短字符串,依旧是0结尾
  };

 public:
  ~TinyString();
  TinyString();
  TinyString(const char* str);
  TinyString(const char* str, int len);
  TinyString(const std::string& str);
  TinyString(const ThisType& str);
  TinyString(ThisType&& str);
  TinyString& operator=(ThisType&& str);
  TinyString& operator=(ThisType& str);
  TinyString& operator=(const char* str);
  TinyString& operator+=(const ThisType& str);
  TinyString& operator+=(const char* str);
  inline const char* c_str() const { return ptr_impl(); }

  inline void Reset() { destroy(); }
  inline int size() const { return strlen(ptr_impl()); }
  int bytes() const;
  inline bool empty() const { return size() <= 0; }
  operator const char*() const { return c_str(); }
  bool operator<(const ThisType& str) const {
    return scompare(c_str(), size(), str.c_str(), str.size()) < 0;
  }
  bool operator<(const char* str) const {
    return scompare(c_str(), size(), str, str ? strlen(str) : 0) < 0;
  }
  bool operator>(const char* str) const {
    return scompare(c_str(), size(), str, str ? strlen(str) : 0) > 0;
  }
  bool operator>(const ThisType& str) const {
    return scompare(c_str(), size(), str.c_str(), str.size()) > 0;
  }
  inline bool operator==(const ThisType& str) const {
    return strcmp(ptr_impl(), str.ptr_impl()) == 0;
  }
  inline bool operator==(const char* str) const {
    return strcmp(str ? str : blank(), ptr_impl()) == 0;
  }
  bool assign_plus(const char* str, int len, const char* post, int postLen);
  bool assign(const char* str, int len);

 protected:
  static inline int scompare(const char* self, int slen, const char* str,
                             int len) {
    if (slen <= 0 && len <= 0)
      return 0;
    else if (slen <= 0)
      return -1;
    else if (len <= 0)
      return 1;
    return strcmp(self, str);
  }
  inline bool istiny() const { return m_data != nullptr && !haspointer(); }
  inline void destroy() {
    if (!istiny() && m_data) delete[] pointer();
    m_data = nullptr;
  }
  inline bool haspointer() const {
    return ((uintptr_t)m_data & MostBitFlag) != 0;
  }
  inline const char* pointer() const {
    return (const char*)((uintptr_t)m_data & ~MostBitFlag);
  }
  inline void set_pointer(const char* ptr) {
    m_data = (const char*)((uintptr_t)ptr | MostBitFlag);
  }
  inline void set_length(char* data, int total) const {}

 protected:
  // 始终获取字符串指针,如果为null返回空指针,使得上层无需关心null指针
  inline const char* ptr_impl() const {
    return m_data == nullptr
               ? blank()
               : (((uintptr_t)m_data & MostBitFlag)
                      ? (const char*)((uintptr_t)m_data & ~MostBitFlag)
                      : m_raw);
  }
  inline const char* blank() const {
    static const char blank_str[4] = {0, 0, 0, 0};
    return blank_str;
  }
};

// 主要用于解决性能问题
class TempTinyString : public TinyString {
 private:
  // 限定该类型的用途,只能在栈上临时使用,不能被new创建
  // 限定TinyString的哪几个接口为私有,不能被使用
  TempTinyString(const TempTinyString& ts) = delete;
  TempTinyString& operator=(const TempTinyString&) = delete;
  TempTinyString& operator=(const char*) = delete;
  TempTinyString& operator=(const std::string& str) = delete;
  void* operator new(size_t size) = delete;
  using TinyString::assign;
  using TinyString::assign_plus;
  using TinyString::Reset;

 public:
  TempTinyString(const std::string& str) {
    m_data = (const char*)(((uintptr_t)str.c_str()) | MostBitFlag);
  }
  TempTinyString(const char* str) {
    m_data = (const char*)(((uintptr_t)str) | MostBitFlag);
  }
  ~TempTinyString() { m_data = nullptr; }
};
}  // namespace base
}  // namespace qb
